package com.recsmile.sgs.client.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.recsmile.sgs.client.card.Card;
import com.recsmile.sgs.client.card.basic.Peach;
import com.recsmile.sgs.client.card.basic.Wine;
import com.recsmile.sgs.client.card.equips.Equipment;
import com.recsmile.sgs.client.commonds.DealStartGameUIClientCommmand;
import com.recsmile.sgs.client.commonds.DiscardGameUIClientCommand;
import com.recsmile.sgs.client.commonds.GameClientCommand;
import com.recsmile.sgs.client.entity.Game;
import com.recsmile.sgs.client.entity.GameRoom;
import com.recsmile.sgs.client.entity.InvalidPlayerCommandException;
import com.recsmile.sgs.client.entity.PlayerComplete;
import com.recsmile.sgs.client.entity.PlayerCompleteServer;
import com.recsmile.sgs.client.entity.PlayerInfo;
import com.recsmile.sgs.client.entity.TurnStage;

public class TurnGameController implements 
	GameController, 
	WineUsableGameController, 
	PeachUsableGameController,
	EquipmentUsableGameController {

	private final GameRoom room;
	private final Game game;
	private PlayerCompleteServer currentPlayer;
	private TurnStage currentStage;
	
	public TurnGameController(GameRoom room) {
		this.room = room;
		this.game = room.getGame();
		this.currentPlayer = game.findPlayer(0);
		this.currentStage = TurnStage.START_BEGINNING;
	}
	
	public void nextStage() {
		switch (currentStage) {
			case END:
				currentPlayer = game.getNextPlayerAlive(currentPlayer);
				while (currentPlayer.isFlipped()) {
					currentPlayer.flip();
					currentPlayer = game.getNextPlayerAlive(currentPlayer);
				}
				break;
			case DEAL:
				try {
					currentPlayer.setWineUsed(0);
					currentPlayer.resetWineEffective();
					currentPlayer.setAttackUsed(0);
				} catch (InvalidPlayerCommandException e) {
					e.printStackTrace();
				}
				break;
			default:
				break;
		}
		currentStage = currentStage.nextStage();
		proceed();
	}
	
	public PlayerCompleteServer getCurrentPlayer() {
		return currentPlayer;
	}
	
	@Override
	public void proceed() {
		for (PlayerCompleteServer player : game.getPlayers()) {
			if (player.makeAction(this)) {
				return;
			}
		}
		switch (currentStage) {
			case START_BEGINNING:
				currentStage = currentStage.nextStage();
				proceed();
				return;
			case START:
				currentStage = currentStage.nextStage();
				proceed();
				return;
			case DECISION_BEGINNING:
				currentStage = currentStage.nextStage();
				proceed();
				return;
			case DECISION:
				currentStage = currentStage.nextStage();
				proceed();
				return;
			case DRAW:
				game.drawCards(currentPlayer, 2);
				currentStage = currentStage.nextStage();
				proceed();
				return;
			case DEAL_BEGINNING:
				currentStage = currentStage.nextStage();
				proceed();
				return;
			case DEAL:
				for (PlayerCompleteServer player : game.getPlayers()) {
					player.clearDisposalArea();
				}
				room.sendCommandToPlayers(toParamsMap(game.getPlayersInfo(), currentPlayer));
				return;
			case DISCARD_BEGINNING:
				currentStage = currentStage.nextStage();
				proceed();
				return;
			case DISCARD:
				int amount = currentPlayer.getHandCount() - currentPlayer.getCardOnHandLimit();
				if (amount > 0) {
					room.sendCommandToPlayers(toParamsMap0(game.getPlayersInfo(), currentPlayer, amount));
				} else {
					for (PlayerComplete player : game.getPlayers()) {
						player.clearDisposalArea();
					}
					currentStage = currentStage.nextStage();
					proceed();
				}
				return;
			case DISCARD_END:
				currentStage = currentStage.nextStage();
				proceed();
				return;
			case END:
				currentStage = currentStage.nextStage();
				currentPlayer = game.getNextPlayerAlive(currentPlayer);
				while (currentPlayer.isFlipped()) {
					currentPlayer.flip();
					currentPlayer = game.getNextPlayerAlive(currentPlayer);
				}
				proceed();
				return;
			default:
				break;
		}
		
	}
	
	private Map<String, GameClientCommand<?>> toParamsMap(List<PlayerInfo> players, PlayerCompleteServer currentPlayer){
		Map<String, GameClientCommand<?>> p = new HashMap<String, GameClientCommand<?>>();
		for(PlayerInfo playerInfo : players){
			p.put(playerInfo.getName(), new DealStartGameUIClientCommmand(currentPlayer.getPlayerInfo()));
		}
		return p;
	}

	private Map<String, GameClientCommand<?>> toParamsMap0(List<PlayerInfo> players, PlayerCompleteServer currentPlayer, int amonut){
		Map<String, GameClientCommand<?>> p = new HashMap<String, GameClientCommand<?>>();
		for(PlayerInfo playerInfo : players){
			p.put(playerInfo.getName(), new DiscardGameUIClientCommand(currentPlayer.getPlayerInfo(),amonut));
		}
		return p;
	}
	
	public void setCurrentStage(TurnStage stage) {
		this.currentStage = stage;
	}
	
	public void setCurrentPlayer(PlayerCompleteServer player) {
		this.currentPlayer = player;
	}
	
	@Override
	public void onWineUsed(Card card) {
		try {
			if (card != null) { 
				if (!(card instanceof Wine)) {
					throw new InvalidPlayerCommandException("card " + card + " is not wine");
				}
				if (!currentPlayer.getCardsOnHand().contains(card)) {
					throw new InvalidPlayerCommandException("card " + card + " is not on current player's hand");
				}
			}
			if (currentPlayer.isWineUsed()) {
				throw new InvalidPlayerCommandException("wine is already used");
			}
			currentPlayer.useCard(card);
			currentPlayer.useWine();
			proceed();
		} catch (InvalidPlayerCommandException e) {
			e.printStackTrace();
		}
		proceed();
	}
	
	@Override
	public void onPeachUsed(Card card) {
		try {
			if (card != null) { 
				if (!(card instanceof Peach)) {
					throw new InvalidPlayerCommandException("card " + card + " is not peach");
				}
				if (!currentPlayer.getCardsOnHand().contains(card)) {
					throw new InvalidPlayerCommandException("card " + card + " is not on current player's hand");
				}
			}
			if (currentPlayer.getHealthCurrent() == currentPlayer.getHealthLimit()) {
				throw new InvalidPlayerCommandException("player health is maximum");
			}
			currentPlayer.useCard(card);
			currentPlayer.changeHealthCurrentBy(1);
		} catch (InvalidPlayerCommandException e) {
			e.printStackTrace();
		}
		proceed();
	}
	
	@Override
	public void onEquipped(Equipment equipment) {
		try {
			currentPlayer.removeCardFromHand(equipment);
			currentPlayer.equip(equipment);
		} catch (InvalidPlayerCommandException e) {
			e.printStackTrace();
		}
		proceed();
	}

}